home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1994 October / Macformat17.cdr / Shareware City / Developers / MungeImage Source / MyDriver.p < prev    next >
Text File  |  1994-05-06  |  14KB  |  474 lines

  1. unit MyDriver;
  2.  
  3. { Code thanks to Pete Resnick }
  4.  
  5. interface
  6.  
  7.     const
  8.         dOpened = $0020;
  9.         dRAMBased = $0040;
  10.  
  11. { Structure of the driver resource }
  12.     type
  13.         DriverRecord = record
  14.                 drvrFlags: integer;
  15.                 drvrDelay: integer;
  16.                 drvrEMask: integer;
  17.                 drvrMenu: integer;
  18.                 drvrOpen: integer;
  19.                 drvrPrime: integer;
  20.                 drvrCtl: integer;
  21.                 drvrStatus: integer;
  22.                 drvrClose: integer;
  23.                 drvrName: str63;
  24. { driver name and code follows }
  25.             end;
  26.         DriverPtr = ^DriverRecord;
  27.         DriverHandle = ^DriverPtr;
  28.         DCtlArray = array[0..1000] of DCtlHandle;
  29.         DCtlArrayPtr = ^DCtlArray;
  30.  
  31. { These two routines are the ones you want to call }
  32.     function InstallRAMDriver (name: Str255; var refnum: integer; openit: boolean): OSErr;
  33.     function RemoveRAMDriver (refnum: integer): OSErr;
  34.  
  35.     function DriverIsOpen (name: Str255): boolean;
  36.  
  37. { These are used internally but might be useful in unusual circumstances }
  38.     function GetDriverRefNum (name: str255): integer;
  39.     function SizeUTable (entries: integer): OSErr;
  40.     function DriverAvail (var unitNum: integer): OSErr;
  41.     function Get1XResource (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  42.     function Get1SysXRsrc (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  43.     function PtrInZone (theZone: THz; thePtr: univ Ptr): boolean;
  44.     function HandleInZone (theZone: THz; theHandle: univ Handle): boolean;
  45.  
  46. { Undefined, but documented routines }
  47.     function DriverInstall (drvrHandle: handle; refnum: integer): OSErr;
  48.     inline
  49.         $301F, $205F, $2050, $A03D, $3E80;
  50.     function DriverRemove (refnum: integer): OSErr;
  51.     inline
  52.         $301F, $A03E, $3E80;
  53.  
  54. { Interupt enable/disable }
  55.     function DisableInterrupts: integer;
  56.     inline
  57.         $4007, $46FC, $2600;
  58.     procedure ResetStatusRegister (oldSR: integer);
  59.     inline
  60.         $46DF;
  61.  
  62. { Access low memory globals }
  63.     function LMUTableBase: DCtlArrayPtr;
  64.     inline
  65.         $2EB8, $011C;
  66.  
  67.     procedure LMSetUTableBase (addr: univ DCtlArrayPtr);
  68.     inline
  69.         $21DF, $011C;
  70.  
  71.     function LMUnitEntryCount: integer;
  72.     inline
  73.         $3EB8, $1D2;
  74.  
  75.     procedure LMSetUnitEntryCount (n: integer);
  76.     inline
  77.         $31DF, $01D2;
  78.  
  79. implementation
  80.  
  81. { *    The following code is to install and remove RAM drivers in the system}
  82. { *    heap. Written by Pete Resnick with the help of J. Geagan, Joe Holt,}
  83. { *    Tom Johnson, Michael A. Libes, Charles Martin, John Norstad, Phil}
  84. { *    Shapiro, Eric Braun, David Brown and Matthias Urlichs. Feel free to}
  85. { *    use this in your code, though I do ask that you give credit. Please}
  86. { *    report any bugs to Pete Resnick - resnick@cogsci.uiuc.edu. Please read}
  87. { *    the README file and check defines in drvrincludes.h before you use}
  88. { *    this code!!}
  89. { *}
  90. { *    Change Log}
  91. { *    ----------}
  92. { *    Date:        Change:                                                Who:}
  93. { *    -----        -------                                                ----}
  94. { *    6/2/92        Changed ThinkCleanup so that it compiles and works    pr}
  95. { *    6/22/92        Corrected declaration of DisableInterrupts            eb}
  96. { *    7/1/92        Corrected declaration of DrvrInstall and DrvrRemove    eb/pr}
  97. { *    10/15/92    Changed Get1SysRsrc to Get1SysXRsrc                    pr}
  98. { *    10/18/92    Got rid of thinkReOpen; just return 1 from close    pr}
  99. { *                Fixed up PtrInZone to make it a little quicker        pr}
  100. { *    11/6/92        Got rid of auto initialize for newCode and oldCode    pr}
  101. { *                Changed PBxxx calls to PBxxxSync                    pr}
  102. { *    11/8/92        A little cleanup; moved a few things                pr}
  103. { *    12/17/92    Added HNoPurge to Get1SysXRsrc                        db/pr}
  104. { *    1/24/93        Fixed double deletion of DATA handle and dispose    db/pr}
  105. { *                of code handle -- major changes to all ThinkXXX}
  106. { *                routines and THINKProc.c}
  107. { *    2/5/93        Made DriverAvail a little more efficent                pr}
  108. { *    2/6/93        Re-wrote all of the Think routines and THINKProc.c    pr}
  109. { *                so that the THINK proc is a pointer instead of a}
  110. { *                handle (needed for locked drivers).}
  111. { *    2/23/93        Passed drvrInstFlags to RemoveRAMDriver    from        pr}
  112. { *                InstallRAMDriver error}
  113. { *    10/21/93    Check for nil handles in RemoveRAMDriver            pr}
  114. { *                Zero out close block in RemoveRAMDriver}
  115. { *                Prettified GetDriverRefNum}
  116. { *                Moved DisableInterrupts, ResetInterrupts,}
  117. { *                DrvrInstall, and DrvrRemove from driver.h to}
  118. { *                drvrincludes.h}
  119. { *                    }
  120. { *    19940212    Convert to Pascal                PNL}
  121.  
  122.  
  123. { *    InstallRAMDriver will install the named driver into the system heap}
  124. { *    return the driver reference number in refNum. }
  125.  
  126.     function InstallRAMDriver (name: Str255; var refnum: integer; openit: boolean): OSErr;
  127.         var
  128.             err, junk: OSErr;
  129.             drvrHandle: handle;
  130.             rsrcType: ResType;
  131.             rsrcID, unitNum: integer;
  132.             hndlState: signedByte;
  133.             ctlEntryPtr: DCtlPtr;
  134.             drvrPtr: DriverPtr;
  135.             pb: ParamBlockRec;
  136.     begin
  137.  
  138.         err := noErr;
  139.  
  140.         if GetDriverRefNum(name) <> 0 then
  141.             err := badUnitErr;
  142.  
  143.         if err = noErr then
  144.             err := DriverAvail(unitNum);
  145.  
  146.         if err = noErr then
  147.             err := Get1SysXRsrc(drvrHandle, 'DRVR', 0, 0, @name);
  148. { Why not just rely on the resource being set to system and non-purgeable and just use Get1NamedResource??? }
  149.  
  150.         if err = noErr then begin
  151.             GetResInfo(drvrHandle, rsrcID, rsrcType, name);
  152.             err := ResError;
  153.  
  154.             if err = noErr then begin
  155.                 DetachResource(drvrHandle);
  156.                 err := ResError;
  157.             end;
  158.  
  159.             if err <> noErr then
  160.                 ReleaseResource(drvrHandle);
  161.         end;
  162.  
  163.         if err = noErr then begin
  164.  
  165.     { Install DRVR with the refNum.  }
  166.             refnum := -(unitNum + 1);
  167.             hndlState := HGetState(drvrHandle);
  168.             HLock(drvrHandle);
  169.             err := DriverInstall(drvrHandle, refnum);
  170.             HSetState(drvrHandle, hndlState);
  171.  
  172.     { Cleanup on errors }
  173.             if err <> noErr then
  174.                 DisposHandle(drvrHandle);
  175.         end;
  176.  
  177.         if err = noErr then begin
  178.     { Move the important information to the driver entry }
  179.             ctlEntryPtr := GetDCtlEntry(refnum)^;
  180.             drvrPtr := DriverHandle(drvrHandle)^;
  181.             ctlEntryPtr^.dCtlDriver := ptr(drvrHandle);
  182.             ctlEntryPtr^.dCtlFlags := BOR(drvrPtr^.drvrFlags, dRAMBased);
  183.             ctlEntryPtr^.dCtlDelay := drvrPtr^.drvrDelay;
  184.             ctlEntryPtr^.dCtlEMask := drvrPtr^.drvrEMask;
  185.             ctlEntryPtr^.dCtlMenu := drvrPtr^.drvrMenu;
  186.  
  187.     { Open the driver }
  188.             if openit then begin
  189.                 pb.ioCompletion := nil;
  190.                 pb.ioNamePtr := @name;
  191.                 pb.ioPermssn := fsCurPerm;
  192.                 err := PBOpenSync(@pb);
  193.             end;
  194.  
  195.     { If an error occurred during the open, remove the DRVR }
  196.             if err <> noErr then
  197.                 junk := RemoveRAMDriver(refnum);
  198.         end;
  199.  
  200.         InstallRAMDriver := err;
  201.     end;
  202.  
  203.  
  204. { *    RemoveRAMDriver removes the driver installed in the system heap by}
  205. { *    InstallRAMDriver.}
  206.  
  207.     function RemoveRAMDriver (refnum: integer): OSErr;
  208.         var
  209.             err: OSErr;
  210.             drvrHandle: handle;
  211.             ctlEntryHndl: DCtlHandle;
  212.             pb: ParamBlockRec;
  213.             hndlState: SignedByte;
  214.     begin
  215.         err := noErr;
  216.  
  217.     { Get the driver control entry }
  218.         ctlEntryHndl := GetDCtlEntry(refNum);
  219.         if ctlEntryHndl = nil then
  220.             err := unitEmptyErr;
  221.  
  222.     { Check for nil handle }
  223.         if (err = noErr) & (ctlEntryHndl^ = nil) then
  224.             err := nilHandleErr;
  225.  
  226.         if err = noErr then begin
  227.     { Get the driver handle }
  228.             drvrHandle := handle(ctlEntryHndl^^.dCtlDriver);
  229.  
  230. { close the driver }
  231.             if BAND(ctlEntryHndl^^.dCtlFlags, dOpened) <> 0 then begin
  232.                 pb.ioResult := 0;
  233.                 pb.ioNamePtr := nil;
  234.                 pb.ioVRefNum := 0;
  235.                 pb.ioRefNum := refNum;
  236.                 pb.ioPermssn := 0;
  237.                 err := PBCloseSync(@pb);
  238.             end;
  239.  
  240.             if err = noErr then begin
  241.     { Remove the driver }
  242.                 HLock(drvrHandle);
  243.                 err := DriverRemove(refNum);
  244.             end;
  245.  
  246. { Dispose of the driver code (nil-safe) }
  247.             DisposHandle(drvrHandle);
  248.         end;
  249.  
  250.         RemoveRAMDriver := err;
  251.     end;
  252.  
  253.  
  254. { *    GetDriverRefNum simply searches through each driver control entry}
  255. { *    for a driver with the same name as that specified in name.}
  256. { *    If found, the reference number is returned. If no driver is found}
  257. { *    by that name, 0 is returned. Reads the low-memory global UnitNtryCnt.}
  258.  
  259.     function GetDriverRefNum (name: str255): integer;
  260.         var
  261.             unitnum: integer;
  262.             curDCtlHndl: DCtlHandle;
  263.             curDriverPtr: DriverPtr;
  264.     begin
  265.         GetDriverRefNum := 0;
  266.         for unitnum := 0 to LMUnitEntryCount - 1 do begin
  267.             curDCtlHndl := LMUTableBase^[unitnum];
  268.             if curDCtlHndl <> nil then begin
  269.                 curDriverPtr := DriverPtr(curDCtlHndl^^.dCtlDriver); { If this is a RAM driver, it's a handle. ROM is a pointer }
  270.                 if (curDriverPtr <> nil) & (BAND(curDCtlHndl^^.dCtlFlags, dRAMBased) <> 0) then begin
  271.                     curDriverPtr := DriverPtr(handle(curDriverPtr)^);
  272.                 end;
  273.                 if (curDriverPtr <> nil) & EqualString(name, curDriverPtr^.drvrName, false, true) then begin
  274.                     GetDriverRefNum := -(unitNum + 1);
  275.                     leave;
  276.                 end;
  277.             end;
  278.         end;
  279.     end;
  280.  
  281.  
  282. { *    SizeUTable sets the size of the driver unit table.}
  283. { *    Interrupts must be disabled during this operation. Changes the}
  284. { *    low-memory globals UTableBase and UnitNtryCnt.}
  285.  
  286.     function SizeUTable (entries: integer): OSErr;
  287.         var
  288.             newUTableBase, oldUTableBase: ptr;
  289.             oldSR: integer;
  290.             err: OSErr;
  291.     begin
  292.     { Make new Unit Table }
  293.         newUTableBase := NewPtrSysClear(longInt(entries) * SizeOf(DCtlHandle));
  294.         err := MemError;
  295.  
  296.         if err = noErr then begin
  297.     { Any Device Manager action now would be bad! }
  298.             oldSR := DisableInterrupts;
  299.  
  300.     { Move the old Unit Table to the new Unit Table }
  301.             BlockMove(ptr(LMUTableBase), newUTableBase, longInt(LMUnitEntryCount) * SizeOf(DCtlHandle));
  302.             oldUTableBase := ptr(LMUTableBase); { Dispose after re-enabling interupts }
  303.             LMSetUTableBase(newUTableBase);
  304.             LMSetUnitEntryCount(entries);
  305.  
  306.     { Renable interrupts }
  307.             ResetStatusRegister(oldSR);
  308.  
  309.             DisposePtr(oldUTableBase);
  310.         end;
  311.         SizeUTable := err;
  312.     end;
  313.  
  314.  
  315. { *    DriverAvail finds the first available slot in the unit table to}
  316. { *    install the new device driver. It will call SizeUTable if there is}
  317. { *    not enough room in the current unit table. It will return the first}
  318. { *    available slot between LOW_UNIT and UP_UNIT. Reads the low-memory}
  319. { *    global UTableBase and may change as well as read the low-memory global}
  320. { *    UnitNtryCnt.}
  321.  
  322.     const
  323.         LOW_UNIT = 48;        { First Unit Table Entry to use        }
  324.         NEW_UNIT = 64;    { Size of a "normal" Unit Table        }
  325.         MAX_UNIT = 128;    { Maximum size of a Unit Table            }
  326.         UP_UNIT = 4;        { Size to bounce up Unit Table            }
  327.  
  328.     function DriverAvail (var unitNum: integer): OSErr;
  329.         var
  330.             unitIndex: integer;
  331.             UTableSize: integer;
  332.             newsize: integer;
  333.             err: OSErr;
  334.     begin
  335.         err := noErr;
  336.         unitNum := 0;
  337.  
  338.         { Look for an empty slot in what's already there }
  339.         for unitIndex := LOW_UNIT to LMUnitEntryCount - 1 do begin
  340.             if LMUTableBase^[unitIndex] = nil then begin
  341.                 unitNum := unitIndex;
  342.                 leave;
  343.             end;
  344.         end;
  345.  
  346.         if unitnum = 0 then begin
  347.             UTableSize := GetPtrSize(ptr(LMUTableBase)) div SizeOf(DCtlHandle); { the real size of the table }
  348.  
  349.             if (LOW_UNIT < UTableSize) & (LMUnitEntryCount < UTableSize) then begin
  350.                 { We can fit the new entry in the current table }
  351.                 if LMUnitEntryCount < LOW_UNIT then begin { Expand to LOW_UNIT first }
  352.                     LMSetUnitEntryCount(LOW_UNIT);
  353.                 end;
  354.                 unitNum := LMUnitEntryCount;
  355.                 LMSetUnitEntryCount(LMUnitEntryCount + 1);
  356.                 err := noErr;
  357.             end
  358.             else if UTableSize < MAX_UNIT then begin
  359.                 { we *can* increase the table size }
  360.                 newsize := UTableSize + UP_UNIT;
  361.                 if newsize < NEW_UNIT then begin
  362.                     newsize := NEW_UNIT;
  363.                 end
  364.                 else if newsize > MAX_UNIT then begin
  365.                     newsize := MAX_UNIT;
  366.                 end;
  367.                 unitNum := LMUnitEntryCount;
  368.                 err := SizeUTable(newsize);
  369.                 if err <> noErr then begin
  370.                     unitNum := 0;
  371.                 end;
  372.             end
  373.             else begin
  374.                 err := unitTblFullErr;
  375.             end;
  376.         end;
  377.  
  378.         DriverAvail := err;
  379.     end;
  380.  
  381.  
  382. { *    Get1XResource gets a handle to a resource. The resource}
  383. { *    will be retrieved according to resource type and either resource name,}
  384. { *    or resource index, or resource ID, in that order, whichever is}
  385. { *    non-zero.}
  386.  
  387.     function Get1XResource (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  388.         var
  389.             err: OSErr;
  390.     begin
  391.         if rsrcName <> nil then begin
  392.             rsrcHndl := Get1NamedResource(rsrcType, rsrcName^);
  393.         end
  394.         else if rsrcInd <> 0 then begin
  395.             rsrcHndl := Get1IndResource(rsrcType, rsrcInd);
  396.         end
  397.         else begin
  398.             rsrcHndl := Get1Resource(rsrcType, rsrcID);
  399.         end;
  400.         err := ResError;
  401.         if (err = noErr) & (rsrcHndl = nil) then
  402.             err := resNotFound;
  403.         Get1XResource := err;
  404.     end;
  405.  
  406.  
  407. { *    Get1SysXRsrc gets a handle to the requested resource making sure that}
  408. { *    both the resource itself and the master pointer are in the system heap}
  409. { *    and non-purgeable. }
  410.  
  411.     function Get1SysXRsrc (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  412.         var
  413.             savedZone, tempSysZone: THz;
  414.             err, ptrCode: OSErr;
  415.     begin
  416.     { Make sure everything loads in the system heap }
  417.         savedZone := GetZone;
  418.         tempSysZone := SystemZone;
  419.         SetZone(tempSysZone);
  420.         SetResLoad(true);
  421.  
  422.         err := Get1XResource(rsrcHndl, rsrcType, rsrcID, rsrcInd, rsrcName);
  423.         if (err = noErr) & not HandleInZone(tempSysZone, rsrcHndl) then begin
  424.             ReleaseResource(rsrcHndl);
  425.             err := Get1XResource(rsrcHndl, rsrcType, rsrcID, rsrcInd, rsrcName);
  426.         end;
  427.         if (err = noErr) & not HandleInZone(tempSysZone, rsrcHndl) then begin
  428.             ReleaseResource(rsrcHndl);
  429.             err := memAZErr;
  430.         end;
  431.         if err = noErr then begin
  432.             HNoPurge(rsrcHndl);
  433.         end;
  434.  
  435.     { Restore the zone to what it was }
  436.         SetZone(savedZone);
  437.         Get1SysXRsrc := err;
  438.     end;
  439.  
  440.  
  441. { *    PtrInZone just checks to see whether the specified pointer is within}
  442. { *    the specified zone.}
  443.  
  444.     function PtrInZone (theZone: THz; thePtr: univ Ptr): boolean;
  445.         var
  446.             stripMask, testPtr, dataStart, dataLim: longInt;
  447.     begin
  448.         testPtr := longInt(StripAddress(thePtr));
  449.         dataStart := longInt(StripAddress(@theZone^.heapData));
  450.         dataLim := longInt(StripAddress(theZone^.bkLim));
  451.         PtrInZone := (dataStart <= testPtr) & (testPtr < dataLim);
  452.     end;
  453.  
  454.  
  455. { *    HandleInZone just checks to see whether the specified pointer is within}
  456. { *    the specified zone.}
  457.  
  458.     function HandleInZone (theZone: THz; theHandle: univ Handle): boolean;
  459.     begin
  460.         HandleInZone := PtrInZone(theZone, theHandle) & PtrInZone(theZone, theHandle^);
  461.     end;
  462.  
  463.  
  464. { *    DriverIsOpen is self evident }
  465.  
  466.     function DriverIsOpen (name: Str255): boolean;
  467.         var
  468.             refnum: integer;
  469.     begin
  470.         refnum := GetDriverRefNum('.ipp');
  471.         DriverIsOpen := (refnum <> 0) & (BAND(GetDCtlEntry(refnum)^^.dCtlFlags, dOpened) <> 0);
  472.     end;
  473.  
  474. end.